using System;
using System.Collections.Generic;
using System.Threading;
using CastleSample.Core;

namespace CastleSample.UI.Core
{
    public class ModuleManager : IModuleManager
    {
        private ModuleCollection m_Modules = new ModuleCollection();

        /// <summary>
        /// Return collection with all modules loaded
        /// </summary>
        public ModuleCollection Modules
        {
            get { return m_Modules; }
        }

        /// <summary>
        /// Load specified module.
        /// </summary>
        public virtual bool LoadModule(string moduleName)
        {
            // get and valid module setting.
            ModuleSetting setting = GetModuleSetting(moduleName);
            if (setting == null)
            {
                LogService.Error(GetType().FullName, string.Format("module setting of {0} is null.", moduleName));
                return false;
            }
            if (!IsModuleSettingValid(setting))
            {
                LogService.Error(GetType().FullName, string.Format("module setting of {0} is not valid.", moduleName));
                return false;
            }
            // load module instance
            if (setting.Enabled)
            {
                return LoadModule(setting);
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Unload a specified module.
        /// </summary>
        public virtual void UnloadModule(string moduleName)
        {
            IModule module = Modules[moduleName];
            if (module == null)
            {
                LogService.Warn(GetType().FullName,
                    string.Format("Trying to unload a module({0}) not loaded.", moduleName));
                return;
            }
            module.OnUnload();
            Modules.Remove(module);
        }

        /// <summary>
        /// Return a flag of if the module was loaded.
        /// </summary>
        public virtual bool IsModuleLoaded(string moduelName)
        {
            return Modules[moduelName] != null;
        }

        /// <summary>
        /// Load all modules defined in config file.
        /// </summary>
        public virtual void LoadAllModules()
        {
            List<ModuleSetting> settings = GetAllModuleSettings();
            foreach (ModuleSetting setting in settings)
            {
                if (setting.Enabled)
                {
                    LoadModule(setting);
                }
            }

            //TODO: delete this line, it's just for debug.
            Thread.Sleep(3000);
        }

        public virtual void StartAllModules()
        {
            foreach (IModule module in m_Modules)
            {
                module.OnStartup();
            }
        }

        private static ModuleSetting GetModuleSetting(string moduleName)
        {
            ModuleSetting setting = null;
            switch(moduleName.Trim().ToLower())
            {
                case "membershipmodule":
                    setting = new ModuleSetting();
                    setting.Name = moduleName.Trim();
                    setting.FullTypeName = "CastleSample.Modules.Membership.MembershipModule,CastleSample.MembershipModule";
                    setting.Enabled = true;
                    break;
                case "ordermodule":
                    setting = new ModuleSetting();
                    setting.Name = moduleName.Trim();
                    setting.FullTypeName = "CastleSample.Modules.Order.OrderModule,CastleSample.OrderModule";
                    setting.Enabled = true;
                    break;
            }
            return setting;
        }

        private static List<ModuleSetting> GetAllModuleSettings()
        {
            List<ModuleSetting> settings = new List<ModuleSetting>();
            settings.Add(GetModuleSetting("MembershipModule"));
            settings.Add(GetModuleSetting("OrderModule"));
            return settings;
        }

        private bool LoadModule(ModuleSetting setting)
        {
            bool loaded = false;
            try
            {
                Type moduleType = Type.GetType(setting.FullTypeName);
                if (moduleType == null)
                {
                    LogService.Error(GetType().FullName, string.Format("Can not load module {0}.", setting.Name));
                    return false;
                }
                IModule module = Activator.CreateInstance(moduleType) as IModule;
                if (module == null)
                {
                    LogService.Error(GetType().FullName,
                        string.Format("Can not create module instance for {0}.", setting.Name));
                    return false;
                }
                loaded = module.OnLoad();
                if (loaded)
                {
                    module.Name = setting.Name;
                    m_Modules.Add(module);
                }
            }
            catch (Exception ex)
            {
                bool rethrow = ExceptionHandler.HandleException(ex);
                if (rethrow)
                {
                    throw;
                }
            }
            return loaded;
        }

        private static bool IsModuleSettingValid(ModuleSetting setting)
        {
            //TODO: implement module setting validation.
            return true;
        }

        private class ModuleSetting
        {
            private string m_Name;

            public string Name
            {
                get { return m_Name; }
                set { m_Name = value; }
            }

            private string m_FullTypeName;

            public string FullTypeName
            {
                get { return m_FullTypeName; }
                set { m_FullTypeName = value; }
            }

            private bool m_Enabled = true;

            public bool Enabled
            {
                get { return m_Enabled; }
                set { m_Enabled = value; }
            }
        }
    }
}